#ifndef MODMSG_H
#define MODMSG_H

#include "DataFlow.h"
#include "MsgManager.h"
#include <windows.h>
#include <stdlib.h>
#include <list>

using std::list;

#define MSG_THREAD_EXIT 1000


typedef struct SMsg
{
    unsigned int	type;
	T_LParameter	lp;
} T_SMsg;

class CMsgModPC : public CMsgMod
{
public:
    //void MInit();
    void StartMsgThread()
    {
        DWORD id;
        if (!hConsumer1)
            hConsumer1 = CreateThread (NULL, 0, ThreadFunction, (PVOID)this, 0, &id);
    }

    static DWORD WINAPI ThreadFunction( PVOID p )
    {
        CMsgModPC * mm = (CMsgModPC *) p;
        DWORD dwWaitResult;

        while (1)
        {
            EnterCriticalSection ( &mm->ListLock );

            while (mm->MsgList.size() == 0)
            {
                // Buffer is empty - sleep so producers can create items.
                //SleepConditionVariableCS (&mm->ListNotEmpty, &mm->ListLock, INFINITE);
                LeaveCriticalSection (&mm->ListLock);
                dwWaitResult = WaitForSingleObject(mm->ListNotEmpty, INFINITE);
                switch (dwWaitResult)
                {
                case WAIT_OBJECT_0:
                    // printf("All threads ended, cleaning up for application exit...\n");
                    break;
                default:
                    printf("WaitForMultipleObjects failed (%d)\n", GetLastError());
                    return 1;
                }
                EnterCriticalSection ( &mm->ListLock );
            }

            list<struct SMsg>::iterator	listit = mm->MsgList.begin();
            list<DataFlow>::iterator datait = mm->MsgData.begin();
            DataFlow data = *datait;
            T_SMsg msg = *listit;
            mm->MsgList.pop_front();
            mm->MsgData.pop_front();

            /*if (StopRequested == TRUE && QueueSize == 0)
            {
                LeaveCriticalSection (&BufferLock);
                break;
            }*/
            LeaveCriticalSection (&mm->ListLock);

			if (msg.type == MSG_THREAD_EXIT)
			{
				delete mm;
				return 1;
			}
            //WakeConditionVariable (&mm->ListNotFull);

            mm->MOnRecvMsg(msg.type, msg.lp, data);
        }
        return 0;
    }

	void DeleteClass()
	{
		MPostMsg(MSG_THREAD_EXIT, 0, (char *)0);
	}

    virtual void MPostMsg(unsigned int type, T_LParameter lp, const DataFlow &data)
    {
        EnterCriticalSection (&ListLock);

        T_SMsg msg = { type, lp };
        MsgList.push_front( msg );
        MsgData.push_front( data );

        LeaveCriticalSection (&ListLock);

        // If a consumer is waiting, wake it.
        SetEvent(ListNotEmpty);
        //WakeConditionVariable (&ListNotEmpty);
    }
    //void MGetMsg();
    virtual void MOnRecvMsg(unsigned int type, T_LParameter lp, const DataFlow &data)
    {
    }
    T_ModuleDescriptor GetMD()
    {
        return Self;
    }

public:
    CMsgModPC() :  hConsumer1(0)
    {
        InitializeCriticalSection (&ListLock);

        ListNotEmpty = CreateEvent(NULL, FALSE, FALSE, NULL);

        T_ModuleDescriptor md;
        md = GetMsgManager()->RegisterModule(*this);
        SetMD(md);
    }

    ~CMsgModPC()
    {
        GetMsgManager()->UnRegisterModule( GetMD() );
    }

private:
    void SetMD(T_ModuleDescriptor md)
    {
        Self = md;
    }
    T_ModuleDescriptor Self;

    list<struct SMsg>	MsgList;
    list<DataFlow>		MsgData;


    //CONDITION_VARIABLE ListNotEmpty;
    //CONDITION_VARIABLE ListNotFull;
    CRITICAL_SECTION   ListLock;

    HANDLE ListNotEmpty;

    HANDLE hConsumer1;

    friend class CMsgManager;

};



















#endif